package com.matt.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.matt.commons.exception.BusinessException;
import com.matt.commons.page.PagerQuery;
import com.matt.domain.LiveRoom;
import com.matt.foundation.constant.LiveRoomConstant;
import com.matt.foundation.constant.RedisConstant;
import com.matt.foundation.dto.AreaSettingDTO;
import com.matt.foundation.model.ErrorCode;
import com.matt.foundation.utils.HttpClientUtil;
import com.matt.foundation.utils.JsonValidateUtil;
import com.matt.foundation.utils.YinShiUtil;
import com.matt.foundation.utils.annotation.OptsTrace;
import com.matt.repository.LiveRoomRepository;
import com.matt.service.LiveAddressService;
import com.matt.service.LiveRoomService;
import com.matt.service.remoteCall.SsoCallService;
import com.tuo51.components.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.scheduling.annotation.Scheduled;
import javax.transaction.Transactional;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.matt.foundation.model.ErrorCode.AREA_LIVE_ROOM_DUPLICATE;

/**
 * *******************************
 * Created by Ron.
 * form com.matt
 * on 2017/8/1
 * *******************************
 */
@Service
@Slf4j
public class LiveRoomServiceImpl implements LiveRoomService {

    @Autowired
    private LiveRoomRepository liveRoomRepository;
    @Autowired
    private LiveAddressService liveAddressService;
    @Autowired
    YinShiUtil yinShiUtil;
    @Autowired
    private SsoCallService ssoCallService;

    @Autowired
    private RedisService redisService;

    @Override
    public List<LiveRoom> getRoomByArea(String areaId) {
        return liveRoomRepository.findByAreaId(areaId);
    }

    @Override
    public List<LiveRoom> getActiveRoomByArea(String areaId) {
        return liveRoomRepository.findByAreaIdAndStatus(areaId, LiveRoomConstant.Status.LIVING.codeOf());
    }

    @Override
    public Page getActiveRoomByAreaPage(String areaId, PagerQuery pagerQuery) {
        Pageable pageRequest = PageRequest.of(pagerQuery.getPageNum(), pagerQuery.getPageSize());
        List<LiveRoom> liveRooms = liveRoomRepository.findByAreaIdAndStatus(areaId, LiveRoomConstant.Status.LIVING.codeOf(), pagerQuery.getPageNum() * pagerQuery.getPageSize(), pagerQuery.getPageSize());
        liveAddressService.getPlayUrl(liveRooms);
        Long count = liveRoomRepository.findByAreaIdAndStatusCount(areaId, LiveRoomConstant.Status.LIVING.codeOf());
        return new PageImpl(liveRooms,pageRequest,count == null ? 0L : count);
    }



    @Override
    public List<LiveRoom> getActiveRoomByAreaAndNoChoosen(String areaId, String teachAreaId) {
        List<LiveRoom> liveRooms = liveRoomRepository.findByTeachingAreaIdAndStatus(teachAreaId, LiveRoomConstant.Status.LIVING.codeOf());
        List<LiveRoom> noChoseList = liveRoomRepository.findByAreaIdAndStatusAndTeachingAreaIdIsNull(areaId, LiveRoomConstant.Status.LIVING.codeOf());
        liveRooms.addAll(noChoseList);
        return liveRooms;

    }

    @Override
    public LiveRoom getByIdInArea(String roomId, String areaId) {
        return liveRoomRepository.findByIdAndAreaId(roomId, areaId);
    }

    @Transactional
    @Override
    public LiveRoom add(String url, String HDUrl, String thumbUrl, String yingshiId, String name,
                        Integer type, String areaId,String teachingAreaId, Boolean isActive) {
        LiveRoom room = liveRoomRepository.findFirstByNameAndAreaId(name, areaId);
        if (Objects.nonNull(room))
            throw new BusinessException(AREA_LIVE_ROOM_DUPLICATE, "摄像头名称重复");

        LiveRoom liveRoom = new LiveRoom();
        liveRoom.setUrl(url);
        liveRoom.setHDUrl(HDUrl);
        liveRoom.setThumbUrl(thumbUrl);

        liveRoom.setName(name);
        liveRoom.setCreated(new Date());

        liveRoom.setType(2);
        liveRoom.setTeachingAreaId(teachingAreaId);

        if (isActive != null){
            liveRoom.setActive(isActive);
        }

        liveRoom.setAreaId(areaId);
        liveRoom.setStatus(1);
        liveRoom.setStatusVal("直播中");

        return liveRoomRepository.save(liveRoom);
    }

    @Transactional
    @Override
    public LiveRoom delete(String areaId, String staffId, String liveRoomId){
        LiveRoom liveRoom = liveRoomRepository.findByIdAndAreaId(liveRoomId, areaId);

        if (liveRoom == null){
            throw new BusinessException(AREA_LIVE_ROOM_DUPLICATE, "指定摄像头不存在");
        }

        if (liveRoom.getType() != 2){
            throw new BusinessException(AREA_LIVE_ROOM_DUPLICATE, "萤石云摄像头请通过录像机管理");
        }

        liveRoomRepository.delete(liveRoom);

        return liveRoom;
    }

    @Transactional
    @Override
    public LiveRoom modify(String roomId, String url, String HDUrl, String thumbUrl, String yingshiId,  String name,
                           Integer type, String areaId, String teachingAreaId,  Boolean isActive) {

        LiveRoom room = liveRoomRepository.findFirstByNameAndAreaId(name, areaId);
        if (Objects.nonNull(room) && !roomId.equals(room.getId()))
            throw new BusinessException(AREA_LIVE_ROOM_DUPLICATE, "摄像头名称重复");

        LiveRoom liveRoom = liveRoomRepository.getOne(roomId);
        liveRoom.setUrl(url);
        liveRoom.setHDUrl(HDUrl);
        liveRoom.setThumbUrl(thumbUrl);
        liveRoom.setName(name);
        liveRoom.setTeachingAreaId(teachingAreaId);
        if (isActive != null){
                liveRoom.setActive(isActive);
        }

//        liveRoom.setIsPublic(isPublic);
        return liveRoomRepository.save(liveRoom);
    }

    @Transactional
    @OptsTrace(code = "0600")
    @Override
    public LiveRoom modifyName(String roomId, String name, List<String> time, String areaId) {
        LiveRoom liveRoom = liveRoomRepository.findByIdAndAreaId(roomId, areaId);
        if (null != liveRoom) {
            //TODO 需要变更这里
            String accessToken = null;// ssoCallService.getAreaYinShiToken(areaId);
            String deviceSerial = liveRoom.getDeviceSerial();
            Integer channelNo = liveRoom.getChannelNo();
            if (StringUtils.isEmpty(deviceSerial) || channelNo == null) {
                return null;
            }
            //萤石修改名称
            boolean b = yinShiUtil.updateCameraName(accessToken, deviceSerial, name, channelNo);
            if (b) {
                liveRoom.setName(name);
                if(time.size() > 0){
                    String timeJson = JsonValidateUtil.toJson(time);
                    // 修改时间段
                    liveRoom.setOpenTime(timeJson);
                }
                return liveRoomRepository.save(liveRoom);
            }
        }
        return null;
    }

    @Transactional
    @Override
    public LiveRoom modifyStatus(String roomId, Boolean active, String areaId) {
        LiveRoom liveRoom = liveRoomRepository.findByIdAndAreaId(roomId, areaId);
        liveRoom.setActive(active);
        return liveRoomRepository.save(liveRoom);
    }

    @Override
    public List<LiveRoom> getRoomListPreviewIsNull() {
        List<LiveRoom> liveRoomList = liveRoomRepository.findByThumbUrlIsNull();
        return liveRoomList;
    }

    @Override
    public List<LiveRoom> getAllRoomList() {
        List<LiveRoom> liveRoomList = liveRoomRepository.findByStatus(LiveRoomConstant.Status.LIVING.codeOf());
        return liveRoomList;
    }

//    @Transactional
//    @Override
//    public boolean updateThumbUrlByYinshiId(String yingShiId, String url) {
//        List<LiveRoom> byYingshiId = liveRoomRepository.findByYingshiId(yingShiId);
//        List<LiveRoom> newList = Lists.newArrayList();
//        byYingshiId.stream().forEach(o -> {
//            o.setThumbUrl(url);
//            newList.add(o);
//        });
//        List<LiveRoom> save = liveRoomRepository.saveAll(newList);
//        return save.size() > 0;
//    }

    @Transactional
    @Override
    public LiveRoom updateThumbUrlById(String areaId, String id, String url){
        LiveRoom lr = liveRoomRepository.findByIdAndAreaId(id, areaId);
        lr.setThumbUrl(url);

        LiveRoom save = liveRoomRepository.save(lr);

        return save;
    }

    @Override
    public String getAreaYinShiToken(String areaId) {

        if (StringUtils.isEmpty(areaId)){
            throw new BusinessException(ErrorCode.PARAM_CAN_NOT_BLANK, "参数错误");
        }

        String redisKey = RedisConstant.YIN_SHI_TOKEN_KEY+ "_" + areaId;
        String token = redisService.getValue(redisKey);
        if (StringUtils.isBlank(token)) {
            AreaSettingDTO yk = ssoCallService.getAreaSetting("ysKey", areaId);
            AreaSettingDTO ys = ssoCallService.getAreaSetting("ysSecret", areaId);

            if (yk == null || ys == null || StringUtils.isNotEmpty(yk.getValue()) || StringUtils.isNotEmpty(ys.getValue())){
                throw new BusinessException(ErrorCode.HAS_NOT_AUDITOR, "需要配置！");
            }

            String ysKey = yk.getValue();
            String ysSecret = ys.getValue();

            token = yinShiUtil.getAccessToken(ysKey, ysSecret);
            if(StringUtils.isNotEmpty(token)) {
                redisService.saveValue(redisKey, RedisConstant.YIN_SHI_TOKEN_EXPIRED_TIME, token);
            }
        }

        return token;
    }


    @Override
    public String getLiveRoomHLSAddress(LiveRoom liveRoom){
        if (liveRoom.getType() == 1) {
            String accessToken = getAreaYinShiToken(liveRoom.getAreaId());

            Map result = yinShiUtil.getCameraPlayAddress(accessToken, liveRoom.getDeviceSerial(), liveRoom.getChannelNo());

            if (result == null) {
                return null;
            }

            return (String) result.get("url");
        }else{
            return liveRoom.getUrl();
        }
    }

    @Override
    public void updateDate(String liveRoomId) {
        LiveRoom liveRoom = liveRoomRepository.getOne(liveRoomId);
        if (Objects.isNull(liveRoom)){
            throw new BusinessException(ErrorCode.PARAM_CAN_NOT_BLANK, "摄像头ID错误");
        }
        liveRoom.setPlayerHeartBeat(new Date());
        liveRoomRepository.save(liveRoom);
    }

    private int getCameraStatus(LiveRoom liveRoom){
        if (StringUtils.isEmpty(liveRoom.getIpUrl())
                || StringUtils.isEmpty(liveRoom.getIpChannel())
                || StringUtils.isEmpty(liveRoom.getIpAuth()) ){
            return -1;
        }

        String statusUrl = liveRoom.getIpUrl() + "jsonfile/rtmpstatus";
        String statusJson = null;
        try {
            //{"rtmpstatus":["2","1","2","2","2","2","2","2","2","2","2","2","2","2","2","2"]}
            statusJson = HttpClientUtil.sendGet(statusUrl).toString();
        } catch (IOException e) {
            return 0;
        }

        if (StringUtils.isBlank(statusJson)){
            return 0;
        }

        if (StringUtils.isNotEmpty(liveRoom.getIpChannel())){
            JSONObject json = JSON.parseObject(statusJson);
            List<String>  stringList  = JSON.parseArray( json.getString("rtmpstatus"),String.class);
            //通道状态
            int channel = Integer.parseInt(liveRoom.getIpChannel());
            if (channel >= 0 && stringList.size() > channel){
                String  s = stringList.get(channel);
                if (StringUtils.equals(s,"2")){
                    return 1;
                }
            }

            //TODO:  同时刷新其他设备
        }

        return 0;
    }

    private int setCameraStatus(LiveRoom liveRoom, boolean online){

        if (StringUtils.isEmpty(liveRoom.getIpUrl())
                || StringUtils.isEmpty(liveRoom.getIpChannel())
                || StringUtils.isEmpty(liveRoom.getIpAuth()) ){
            return -1;
        }

        String val = online ? "start" : "stop";

        String url = liveRoom.getIpUrl() + "control?command=live_control&channel="
                +liveRoom.getIpChannel() + "&value=" + val + "&auth=" + liveRoom.getIpAuth();
        //打开摄像头
        String responseJson = null;
        try {
            responseJson = HttpClientUtil.sendPost(url, null, null).toString();
        } catch (IOException e) {
            return -1;
//            throw new BusinessException(ErrorCode.GENRAL_INTERNAL_ERROR, "物联网设备通信失败");
        }

        if (StringUtils.isBlank(responseJson)){
            return 0;
        }

        if (responseJson.equals("ok")){
            return 1;
        }

//        JSONObject json = JSON.parseObject(responseJson);
//        List<String> stringList = JSON.parseArray( json.getString("rtmpstatus"),String.class);
//        //通道状态
//        if (stringList.size() >= Integer.parseInt(liveRoom.getIpChannel()) ){
//            String  s = stringList.get(Integer.parseInt(liveRoom.getIpChannel()) );
//            if (StringUtils.equals(s,"2")){
//                return true;
//            }
//        }

        return 0;
    }


    //同步摄像头状态
    @Async
    protected void SyncCameraStatus(LiveRoom liveRoom){
        //大于5分钟直接返回，防止重复调用
        if (Objects.nonNull(liveRoom.getLastModify())){
            if (liveRoom.getLastModify().getTime() > new Date().getTime() - (1000*60*5)){
                return;
            }
        }

        int ret = getCameraStatus(liveRoom);

        if (ret == -1){

        }else if (ret == 1){
            if (!liveRoom.getIpOnline()){
                liveRoom.setIpOnline(true);
                liveRoom.setPlayerHeartBeat(new Date());
                liveRoom.setLastModify(new Date());
                liveRoomRepository.save(liveRoom);
            }
        }else if (liveRoom.getIpOnline()){
            liveRoom.setLastModify(new Date());
            liveRoom.setIpOnline(false);
            liveRoomRepository.save(liveRoom);
        }
    }

    @Override
    public Integer openLive(LiveRoom liveRoom){
        if (Objects.isNull(liveRoom)){
            throw new BusinessException(ErrorCode.PARAM_CAN_NOT_BLANK, "摄像头ID错误");
        }

        //打开摄像头
        if (liveRoom.getIpOnline()){
            SyncCameraStatus(liveRoom);
            return 0;
        }
        int status =  setCameraStatus(liveRoom, true);
        //设置状态
        if ( status== 1){
            liveRoom.setIpOnline(true);
            liveRoom.setPlayerHeartBeat(new Date());
            liveRoom.setLastModify(new Date());
            liveRoomRepository.save(liveRoom);
            return 1;
        }
        //摄像头处于无法打开时候抛出异常
        if (status == -1){
            throw new BusinessException(ErrorCode.GENRAL_INTERNAL_ERROR, "物联网设备通信失败");
        }
        return 0;
    }

    @Override
    public Integer openLive(String areaId, String liveRoomId)  {
        LiveRoom liveRoom = liveRoomRepository.findByIdAndAreaId(liveRoomId, areaId);
        return openLive(liveRoom);
    }

    @Override
    public LiveRoom closeLive(LiveRoom liveRoom)  {
         if (setCameraStatus(liveRoom, false) == 1){
             liveRoom.setIpOnline(false);
             liveRoom.setLastModify(null);
             liveRoomRepository.save(liveRoom);
        }

        return liveRoom;
    }

    @Override
    public LiveRoom closeLive(String areaId, String liveRoomId)  {
        LiveRoom liveRoom = liveRoomRepository.findByIdAndAreaId(liveRoomId, areaId);
        if (Objects.isNull(liveRoom)){
            throw new BusinessException(ErrorCode.PARAM_CAN_NOT_BLANK, "摄像头ID错误");
        }

        return closeLive(liveRoom);
    }

    @Override
    public void shutdownAllDeadCamera(){
        long now = System.currentTimeMillis();
        long before = now - (30 * 60 * 1000);  //三十分钟以前

        Date param = new Date(before);

        List<LiveRoom> deadCameras = liveRoomRepository.findAllDeadCameras(param, 0, 1000);
        long count = liveRoomRepository.countAllDeadCameras(param);

        log.info("got dead cameras: "  + count );

        for (int i = 0; i < deadCameras.size(); i++){
            LiveRoom l = deadCameras.get(i);

            log.info("try to close camera : {} - {} - {}", l.getIpUrl(), l.getIpAuth(), l.getIpChannel());

            getCameraStatus(l);
            closeLive(l);

        }
    }

//    @Scheduled(cron = "0 0/5 * * * ? ")   //从0分钟开始，每5分钟执行一次
//    public void cleanDeadCamerasScheduler(){
//        shutdownAllDeadCamera();
//    }

}
